#include "mainwindow.h"
#include <QtGui>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    topBar = new TopBar(this);
    topBar->changeIconBorder(TopBar::LBRTRounded);

    about = new About(this);

    twit_queue = new Queue(this);

    settingsDialog = new Settings(this);

    QPushButton *friendsTLBtn = new QPushButton(tr("Friends"), this);
        friendsTLBtn->setCheckable(true);
        friendsTLBtn->setObjectName("TabButton");
        friendsTLBtn->setChecked(true);
    QPushButton *publicTLBtn = new QPushButton(tr("Public"), this);
        publicTLBtn->setCheckable(true);
        publicTLBtn->setObjectName("TabButton");
    QPushButton *userTLBtn = new QPushButton(tr("User"), this);
        userTLBtn->setCheckable(true);
        userTLBtn->setObjectName("TabButton");
    QPushButton *mentionsTLBtn = new QPushButton(tr("Mentions"), this);
        mentionsTLBtn->setCheckable(true);
        mentionsTLBtn->setObjectName("TabButton");

        twitTabsGrp = new QButtonGroup(this);
            twitTabsGrp->addButton(friendsTLBtn, Friends);
            twitTabsGrp->addButton(publicTLBtn, Public);
            twitTabsGrp->addButton(userTLBtn, User);
            twitTabsGrp->addButton(mentionsTLBtn, Mentions);
            twitTabsGrp->setExclusive(true);

    connect(twitTabsGrp, SIGNAL(buttonClicked(int)), this, SLOT(twitTabsClicked(int)));

    twitTabs = new QToolBar(tr("Tabs"));
        twitTabs->setObjectName("TwitTabs");
        twitTabs->setFloatable(false);
        twitTabs->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea);
        twitTabs->addWidget(friendsTLBtn);
        twitTabs->addWidget(publicTLBtn);
        twitTabs->addWidget(userTLBtn);
        twitTabs->addWidget(mentionsTLBtn);

    topToolBar = new QToolBar(tr("TopBarDock"));
        topToolBar->setObjectName("TopBarDock");
        topToolBar->setFloatable(false);
        topToolBar->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea);
        topToolBar->addWidget(topBar);


    twitList = new TwitList(this);

    QScrollArea *scrollArea = new QScrollArea(this);
    scrollArea->setWidgetResizable(true);
    scrollArea->setWidget(twitList);
    scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

    twitLib = new QTwitLib();

    statusBar = new StatusBar(this);
    setStatusBar(statusBar);

    QVBoxLayout *mainLayout = new QVBoxLayout();
    mainLayout->addWidget(scrollArea);
    mainLayout->setMargin(0);
    mainLayout->setSpacing(0);

    QWidget *centralWidget = new QWidget(this);
    centralWidget->setLayout(mainLayout);

    setCentralWidget(centralWidget);
    addToolBar(twitTabs);
    insertToolBar(twitTabs, topToolBar);
    insertToolBarBreak(twitTabs);

    setWindowTitle(qApp->property("appRealName").toString());
    setWindowIcon(QIcon(":/images/qwitik16.png"));

    updateByClickTimer = new QTimer(this);
        updateByClickTimer->setInterval(DEFAULT_UPD_BY_CLICK_TIME);
        connect(updateByClickTimer, SIGNAL(timeout()), this, SLOT(allowUpdateByClick()));

    updateTimer = new QTimer(this);
        connect(updateTimer, SIGNAL(timeout()), this, SLOT(updateTimeOut()));

    twitterStatusTimer = new QTimer(this);
        twitterStatusTimer->setInterval(DEFAULT_TWITTERUP_STATUS_CHECK_TIME);
//        twitterStatusTimer->start();
        connect(twitterStatusTimer, SIGNAL(timeout()), this, SLOT(checkTwitterStatus()));

    connect(twitLib, SIGNAL(OnResponseReceived(Returnables::Response*)), this, SLOT(OnResponseReceived(Returnables::Response*)));
    connect(twitLib, SIGNAL(OnStatusReceived(SERVER::RESP)), this, SLOT(OnStatusReceived(SERVER::RESP)));
    connect(twitLib, SIGNAL(OnError(QHttp::Error)), this, SLOT(OnError(QHttp::Error)));
    connect(twit_queue, SIGNAL(lostAnswer()), twitLib, SLOT(Abort()));
    connect(twit_queue, SIGNAL(networkError()), twitLib, SLOT(Abort()));

    connect(settingsDialog, SIGNAL(newLoginInfo()), this, SLOT(ReLogin()));
    connect(settingsDialog, SIGNAL(settingsChanged()), this, SLOT(initSettings()));


    connect(topBar, SIGNAL(updateStatus(QString)), this, SLOT(sendStatus(QString)));

    connect(twit_queue, SIGNAL(returnCommand(Returnables::RequestId,QList<QVariant>)), this, SLOT(runCommand(Returnables::RequestId, QList<QVariant>)));
    connect(twit_queue, SIGNAL(stateChanged(Queue::STATE)), statusBar, SLOT(setStatusIcon(Queue::STATE)));

    connect(twitList, SIGNAL(replyClicked(QString)), this, SLOT(replyClicked(QString)));
    connect(twitList, SIGNAL(TrashClicked(uint)), this, SLOT(trashClicked(uint)));
    connect(twitList, SIGNAL(favoritClicked(uint,bool)), this, SLOT(favoritClicked(uint,bool)));


    init();
}

void MainWindow::init()
{
    createSysTray();
    initSettings();

    setSkin();

    initLogin();
}

void MainWindow::initSettings()
{
    qDebug() << "MainWindow::initSettings()";
    //MainWindow
    resize(settingsDialog->getWindowSize());
    move(settingsDialog->getWindowPosition());
    restoreState(settingsDialog->getToolBarState());

    //TwitListElement
    twitList->setStatusOwnerColor(settingsDialog->getStatusOwnerColor());
    twitList->setUsersColor(settingsDialog->getUsersColor());
    twitList->setLinksColor(settingsDialog->getLinksColor());
    twitList->setStatusOwnerBold(settingsDialog->getIsStatusOwnerBold());
    twitList->setUsersBold(settingsDialog->getIsUsersBold());
    twitList->setLinksBold(settingsDialog->getIsLinksBold());
    twitList->setCacheDir(settingsDialog->getCacheDir());


    //Login Information
    QString userName = settingsDialog->getUsername();
    QString userPass = settingsDialog->getPassword();
    if(!userName.isEmpty() && !userPass.isEmpty())
    {
        twitLib->SetLoginInfo(userName, userPass);
//        checkTwitterStatus();
//        updateTwitTabs(0);
//        privTabState = Friends;
    } else {
        settingsDialog->show();
    }

    //Timers
    updateTimer->setInterval(settingsDialog->getUpdateTime());
}

void MainWindow::initLogin()
{
    state = MainWindow::LOGIN;
    QList<QVariant> param;
    twit_queue->addCommand(Returnables::VERIFY_CREDENTIALS, param);
}

void MainWindow::ReLogin()
{
    state = MainWindow::RELOGIN;
    twit_queue->reset();
    twitLib->SetLoginInfo(settingsDialog->getUsername(), settingsDialog->getPassword());
    QList<QVariant> param;
    twit_queue->addCommand(Returnables::VERIFY_CREDENTIALS, param);
}

//Tabs
//==================================================================================================
void MainWindow::twitTabsClicked(int i)
{
    TwitTabsButton button = static_cast<TwitTabsButton>(i);

    if(button == privTabState)
    {
        return;
    } else {
        privTabState = button;
    }
    updateTwitTabs(i);
}

void MainWindow::allowUpdateByClick()
{
    updateByClickTimer->stop();
    privTabState = Nothing;
}

void MainWindow::updateTimeOut()
{
    qDebug() << "MainWindow::updateTimeOut()";
    updateTwitTabs(twitTabsGrp->checkedId());
}

void MainWindow::updateTwitTabs(int i)
{
    TwitTabsButton button = static_cast<TwitTabsButton>(i);
    switch(button)
    {
        case MainWindow::Friends:
        {
            QList<QVariant> param;
            twit_queue->addCommand(Returnables::FRIENDS_TIMELINE, param);
        break;
        }
        case MainWindow::Public:
        {
            QList<QVariant> param;
            twit_queue->addCommand(Returnables::PUBLIC_TIMELINE, param);
        break;
        }
        case MainWindow::User:
        {
            QList<QVariant> param;
            twit_queue->addCommand(Returnables::USER_TIMELINE, param);
        break;
        }
        case MainWindow::Mentions:
        {
            QList<QVariant> param;
            twit_queue->addCommand(Returnables::RECENT_MENTIONS, param);
        }
    }
    updateByClickTimer->start();
}
//==================================================================================================

//Twitter Status
//==================================================================================================
void MainWindow::checkTwitterStatus()
{
    QList<QVariant> param;
    twit_queue->addCommand(Returnables::TWITTER_UP, param);
}
//==================================================================================================

//ToolBars Position Settings
//==================================================================================================
void MainWindow::updateToolBarsState()
{
    settingsDialog->updateToolBarState(saveState());
}
//==================================================================================================

void MainWindow::sendStatus(QString status)
{
    QList<QVariant> param;
    param.append(status);
    twit_queue->addCommand(Returnables::NEW_STATUS, param);
}

void MainWindow::OnError(QHttp::Error error)
{
    switch(error)
    {
        case QHttp::NoError:
//No error occurred
        break;
        case QHttp::HostNotFound:
//The host name lookup failed.
        break;
        case QHttp::ConnectionRefused:
//The server refused the connection.
        break;
        case QHttp::UnexpectedClose:
//The server closed the connection unexpectedly.
        break;
        case QHttp::InvalidResponseHeader:
//The server sent an invalid response header.
        break;
        case QHttp::WrongContentLength:
//The client could not read the content correctly because an error with respect to the content length occurred.
        break;
        case QHttp::Aborted:
//The request was aborted with abort().
        break;
        case QHttp::ProxyAuthenticationRequiredError:
//QHttp is using a proxy, and the proxy server requires authentication to establish a connection.
        break;
        case QHttp::AuthenticationRequiredError:
//The web server requires authentication to complete the request.
        break;
        case QHttp::UnknownError:
//An error other than those specified above occurred.
        break;
    }
}

void MainWindow::OnStatusReceived(SERVER::RESP resp)
{
    if(resp)
    {
        QString error = NULL;
        switch(resp)
        {
            case SERVER::OK:
                twit_queue->OKanswer();
                if(state == MainWindow::RELOGIN)
                {
                    qDebug() << "MAIN::RELOGIN";
                    settingsDialog->loginCallBack(false);
                    state = MainWindow::RUNNING;
                }
                else if(state == MainWindow::LOGIN)
                {
                    qDebug() << "MAIN::LOGIN";
                    state = MainWindow::RUNNING;
                    updateTimeOut();
                }
                else
                {
                    qDebug() << "MAIN::RUNNING";
                    updateTimer->start();
                }
            break;
            case SERVER::NOT_MODIFIED:
                error = "NOT_MODIFIED(304)";
            break;
            case SERVER::BAD_REQUEST:
                error = "BAD_REQUEST(400)";
            break;
            case SERVER::NOT_AUTHORIZED:
                error = "NOT_AUTHORIZED(401)";
                twit_queue->reset();
                settingsDialog->loginCallBack(true);
            break;
            case SERVER::FORBIDDEN:
                error = "FORBIDDEN(403)";
            break;
            case SERVER::NOT_FOUND:
                error = "NOT_FOUND(404)";
                twit_queue->OKanswer();
            break;
            case SERVER::INTERNAL_SERVER_ERROR:
                error = "INTERNAL_SERVER_ERROR(500)";
            break;
            case SERVER::BAD_GATEWAY:
                error = "BAD_GATEWAY(502)";
            break;
            case SERVER::SERVICE_UNAVAILABLE:
                error = "SERVICE_UNAVAILABLE(503)";
            break;
            case SERVER::UNKNOWN:
                error = "UNKNOWN";
            break;
        }
    }
}

void MainWindow::setSkin()
{
    QFile skinFile(":default.qss");
    skinFile.open(QIODevice::ReadOnly | QIODevice::Text);

    QTextStream skind(&skinFile);
    skin = skind.readAll();
    qApp->setStyleSheet(skin);
}

void MainWindow::OnResponseReceived(Returnables::Response *resp)
{
    if(resp)
    {
    switch(resp->reqID)
    {
        case Returnables::PUBLIC_TIMELINE:
        {
            Returnables::PublicTimeline *pTimeline = static_cast<Returnables::PublicTimeline *>(resp);
                twitList->createList(pTimeline->list);
            delete pTimeline;
            break;
        }
        case Returnables::FRIENDS_TIMELINE:
        {
            Returnables::FriendsTimeline *fTimeline = static_cast<Returnables::FriendsTimeline *>(resp);
                twitList->createList(fTimeline->list);
            delete fTimeline;
            break;
        }
        case Returnables::SINGLE_STATUS:
        {
            Returnables::SingleStatus *singleStatus = static_cast<Returnables::SingleStatus *>(resp);

            delete singleStatus;
            break;
        }
        case Returnables::FEATURED_USERS:
        {
            Returnables::FeaturedUsers *featuredUsers = static_cast<Returnables::FeaturedUsers *>(resp);

            delete featuredUsers;
            break;
        }
        case Returnables::VERIFY_CREDENTIALS:
        {
            Returnables::VerifyCredentials *verifyCredentials = static_cast<Returnables::VerifyCredentials *>(resp);
                topBar->changeName(verifyCredentials->userExt->user.screenName);
                topBar->downloadIcon(verifyCredentials->userExt->user.profileImageUrl);
                twitList->setProfile(*verifyCredentials->userExt);
            delete verifyCredentials;
            break;
        }
        case Returnables::TWITTER_UP:
        {
            Returnables::TwitterUp *twitterUp = static_cast<Returnables::TwitterUp *>(resp);

            delete twitterUp;
            break;
        }
        case Returnables::USER_TIMELINE:
        {
            Returnables::UserTimeline *userTimeline = static_cast<Returnables::UserTimeline *>(resp);
                twitList->createList(userTimeline->list);
            delete userTimeline;
            break;
        }
        case Returnables::FAVORITES:
        {
            Returnables::Favorites *favorites = static_cast<Returnables::Favorites *>(resp);

            delete favorites;
            break;
        }
        case Returnables::NEW_STATUS:
        {
            Returnables::NewStatus *newStatus = static_cast<Returnables::NewStatus *>(resp);
                if (newStatus->status->status.id)
                {
                    updateTimeOut();
                    topBar->clearText();
                    topBar->enableStatusEdit(true);
                } else {
                    topBar->enableStatusEdit(true);
                }
            delete newStatus;
            break;
        }
        case Returnables::RECENT_MENTIONS:
        {
            Returnables::RecentMentions *mentions = static_cast<Returnables::RecentMentions *>(resp);
                twitList->createList(mentions->list);
            delete mentions;
            break;
        }
        case Returnables::REMOVE_STATUS:
        {
            Returnables::RemoveStatus *removedStatus = static_cast<Returnables::RemoveStatus *>(resp);
                if(removedStatus)
                {
                    twitList->removeTrashedStatus(removedStatus->status->status.id);
                }
            delete removedStatus;
            break;
        }
        case Returnables::FRIENDS:
        {
            Returnables::Friends *friends = static_cast<Returnables::Friends *>(resp);

            delete friends;
            break;
        }
        case Returnables::FOLLOWERS:
        {
            Returnables::Followers *followers = static_cast<Returnables::Followers *>(resp);

            delete followers;
            break;
        }
        case Returnables::USER_DETAILS:
        {
            Returnables::UserDetails *userDetails = static_cast<Returnables::UserDetails *>(resp);
//                topBar->changeName(userDetails->user->screenName);
//                topBar->changeText(userDetails->status->text);

            delete userDetails;
            break;
        }
        case Returnables::SENT_DIRECT_MESSAGES:
        {
            Returnables::SentDirectMessages *sentDirectMessages = static_cast<Returnables::SentDirectMessages *>(resp);

            delete sentDirectMessages;
            break;
        }
        case Returnables::RECEIVED_DIRECT_MESSAGES:
        {
            Returnables::ReceivedDirectMessages *receivedDirectMessages = static_cast<Returnables::ReceivedDirectMessages *>(resp);

            delete receivedDirectMessages;
            break;
        }
        case Returnables::SEND_DIRECT_MESSAGE:
        {
            Returnables::SendDirectMessage *sendDirectMessage = static_cast<Returnables::SendDirectMessage *>(resp);

            delete sendDirectMessage;
            break;
        }
        case Returnables::REMOVE_DIRECT_MESSAGE:
        {
            Returnables::RemoveDirectMessage *removeDirectMessage = static_cast<Returnables::RemoveDirectMessage *>(resp);

            delete removeDirectMessage;
            break;
        }
        case Returnables::ADD_FRIENDSHIP:
        {
            Returnables::AddFriendship *addFriendship = static_cast<Returnables::AddFriendship *>(resp);

            delete addFriendship;
            break;
        }
        case Returnables::REMOVE_FRIENDSHIP:
        {
            Returnables::RemoveFriendship *removeFriendship = static_cast<Returnables::RemoveFriendship *>(resp);

            delete removeFriendship;
            break;
        }
        case Returnables::FRIENDSHIP_EXISTS:
        {
            Returnables::FriendshipExist *friendshipExists = static_cast<Returnables::FriendshipExist *>(resp);

            delete friendshipExists;
            break;
        }
        case Returnables::DELIVERY_DEVICE:
        {
            Returnables::DeliveryDevice *deliveryDevice = static_cast<Returnables::DeliveryDevice *>(resp);

            delete deliveryDevice;
            break;
        }
        case Returnables::API_REQUESTS:
        {
            Returnables::ApiRequests *apiRequests = static_cast<Returnables::ApiRequests *>(resp);

            delete apiRequests;
            break;
        }
        case Returnables::ADD_FAVORITE:
        {
            Returnables::AddFavorite *addFavorite = static_cast<Returnables::AddFavorite *>(resp);
                if(addFavorite)
                {
                    twitList->updateFavoritedStatus(addFavorite->status->status.id, addFavorite->status->status.favorited);
                }
            delete addFavorite;
            break;
        }
        case Returnables::REMOVE_FAVORITE:
        {
            Returnables::RemoveFavorite *removeFavorite = static_cast<Returnables::RemoveFavorite *>(resp);
                if(removeFavorite)
                {
                    twitList->updateFavoritedStatus(removeFavorite->status->status.id, removeFavorite->status->status.favorited);
                }
            delete removeFavorite;
            break;
        }
    }
    }
}

void MainWindow::runCommand(Returnables::RequestId comm, QList<QVariant> param)
{
        switch(comm)
        {
            case Returnables::VERIFY_CREDENTIALS:
                twitLib->VerifyCredentials();
            break;
            case Returnables::FRIENDS_TIMELINE:
                twitLib->GetFriendsTimeline();
            break;
            case Returnables::PUBLIC_TIMELINE:
                twitLib->GetPublicTimeline();
            break;
            case Returnables::USER_TIMELINE:
                twitLib->GetUsersTimeline();
            break;
            case Returnables::RECENT_MENTIONS:
                twitLib->GetRecentMentions();
            break;
            case Returnables::TWITTER_UP:
                twitLib->IsTwitterUp();
            break;
            case Returnables::ADD_FAVORITE:
                twitLib->AddFavorite(param[0].toUInt());
            break;
            case Returnables::REMOVE_FAVORITE:
                twitLib->RemoveFavorite(param[0].toUInt());
            break;
            case Returnables::REMOVE_STATUS:
                twitLib->RemoveStatus(param[0].toUInt());
            break;
            case Returnables::NEW_STATUS:
                twitLib->PostNewStatus(param[0].toString());
            break;
        }
}

void MainWindow::replyClicked(QString screenName)
{
    topBar->changeText("@" + screenName + " ");
}

void MainWindow::favoritClicked(uint statusId, bool favorited)
{
    qDebug() << "MainWindow::favoritClicked()";
    QList<QVariant> param;
    param.append(statusId);
    if(favorited)
    {
        twit_queue->addCommand(Returnables::REMOVE_FAVORITE, param);
    } else {
        twit_queue->addCommand(Returnables::ADD_FAVORITE, param);
    }
}

void MainWindow::trashClicked(uint statusId)
{
    QList<QVariant> param;
    param.append(statusId);
    twit_queue->addCommand(Returnables::REMOVE_STATUS, param);
}

void MainWindow::createSysTray()
{
    createTrayMenu();
    sysTrayIcon = new QSystemTrayIcon(QIcon(DEFAULT_TRAY_ICON), this);
    sysTrayIcon->setContextMenu(trayMenu);
    sysTrayIcon->show();
    connect(sysTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(sysTrayActivated(QSystemTrayIcon::ActivationReason)));
}

void MainWindow::createTrayMenu()
{
    createMenuActions();
    trayMenu = new QMenu(this);
    trayMenu->addAction(actShowHide);
    trayMenu->addSeparator();
    trayMenu->addAction(actConfigure);
    trayMenu->addSeparator();
    trayMenu->addAction(actAbout);
    trayMenu->addAction(actAboutQt);
    trayMenu->addSeparator();
    trayMenu->addAction(actExit);
}

void MainWindow::createMenuActions()
{
    actShowHide = new QAction(this);
        connect(actShowHide, SIGNAL(triggered(bool)), this, SLOT(sysTrayShowHide()));
    actConfigure = new QAction(QIcon(DEFAULT_ACT_CONF_ICON), tr("Configure"), this);
        connect(actConfigure, SIGNAL(triggered(bool)), settingsDialog, SLOT(show()));
    actAbout = new QAction(QIcon(DEFAULT_ACT_ABOUT_ICON), tr("About"), this);
        connect(actAbout, SIGNAL(triggered(bool)), about, SLOT(show()));
    actAboutQt = new QAction(QIcon(DEFAULT_ACT_ABOUTQT_ICON), tr("About Qt"), this);
        connect(actAboutQt, SIGNAL(triggered(bool)), qApp, SLOT(aboutQt()));
    actExit = new QAction(QIcon(DEFAULT_ACT_EXIT_ICON), tr("Exit"), this);
        connect(actExit, SIGNAL(triggered(bool)), qApp, SLOT(quit()));
}

void MainWindow::sysTrayActivated(QSystemTrayIcon::ActivationReason reason)
{
    switch (reason){
        case QSystemTrayIcon::Trigger:
            if(isVisible()){
                if(isMinimized()){
                     showNormal();
                 } else {
                     hide();
                 }
            } else {
                show();
            }
        break;
        default:
        break;
    }
}

void MainWindow::sysTrayShowHide()
{
    sysTrayActivated(QSystemTrayIcon::Trigger);
}

void MainWindow::sysTrayShowHideIcon(bool isShow)
{
    if(isShow){
        actShowHide->setIcon(QIcon(DEFAULT_ACT_SHOW_ICON));
        actShowHide->setText(tr("Show"));
    } else {
        actShowHide->setIcon(QIcon(DEFAULT_ACT_HIDE_ICON));
        actShowHide->setText(tr("Hide"));
    }
}

void MainWindow::hideEvent(QHideEvent *)
{
    sysTrayShowHideIcon();
    settingsDialog->updateWindowSize(this->width(), this->height());
    settingsDialog->updateWindowPosition(this->x(), this->y());
}

void MainWindow::showEvent(QShowEvent *)
{
    sysTrayShowHideIcon(false);
    resize(settingsDialog->getWindowSize());
    move(settingsDialog->getWindowPosition());
}

void MainWindow::resizeEvent(QResizeEvent *)
{
    settingsDialog->updateWindowSize(this->width(), this->height());
    settingsDialog->updateWindowPosition(this->x(), this->y());
}

void MainWindow::moveEvent(QMoveEvent *)
{
    settingsDialog->updateWindowPosition(this->x(), this->y());
}

MainWindow::~MainWindow()
{
    updateToolBarsState();
    settingsDialog->updateWindowSize(this->width(), this->height());
    settingsDialog->updateWindowPosition(this->x(), this->y());
}
